﻿using System;

namespace DK.RingLinkedList;
public class RingSingleLinkedList<T>
{

    private LinkedNode<T>? fristNode;
    private LinkedNode<T>? lastNode;

    public LinkedNode<T>? FristNode { get => fristNode; private set => fristNode = value; }
    public LinkedNode<T>? LastNode { get => lastNode; private set => lastNode = value; }

    /// <summary>
    /// 往尾部插入一个数据
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public RingSingleLinkedList<T> Add(T data)
    {
        if (FristNode == null || LastNode == null)
        {
            var node = new LinkedNode<T>(0, data);
            FristNode = node;
            node.Next = node;
            LastNode = node;
        }
        else
        {
            var node = new LinkedNode<T>(LastNode.Index + 1, data);
            LastNode.Next = node;
            node.Next = FristNode;
            LastNode = node;
        }

        return this;
    }

    /// <summary>
    /// 获取
    /// </summary>
    /// <param name="number">下标</param>
    /// <returns></returns>
    /// <exception cref="NullReferenceException">链表空异常</exception>
    public LinkedNode<T> Get(int number) 
    {
        if (FristNode == null || LastNode == null)
        {
            throw new NullReferenceException("linkedlist is null.");
        }

        LinkedNode<T> node = FristNode;

        do
        {
            if (node.Index == number) break;
            node = node.Next;
        }
        while (node != FristNode);

        if (node == FristNode && FristNode.Index == number) throw new IndexOutOfRangeException("not found node.");
        return node;
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="number">下标</param>
    /// <returns></returns>
    /// <exception cref="NullReferenceException"></exception>
    public LinkedNode<T> Delete(int number) 
    {
        if (FristNode == null || LastNode == null)
        {
            throw new NullReferenceException("linkedlist is null.");
        }

        //慢指针
        LinkedNode<T> lownode = FristNode;

        //快指针
        LinkedNode<T> fastnode = FristNode;

        //删除旗标
        var isDeleteFlag = false;

        //删除节点
        LinkedNode<T> deleteNode = null;

        do
        {

            //第一次执行,快慢指针相等情况下
            if (lownode == fastnode)
            {
                //删除的元素为头元素
                if (fastnode.Index == number) 
                {
                    //删除的头元素为最后一个元素
                    if (FristNode == LastNode) 
                    {
                        deleteNode = FristNode;
                        FristNode = null;
                        LastNode = null;
                        return deleteNode;
                    }


                    deleteNode = fastnode;
                    fastnode = fastnode.Next;
                    lownode = fastnode;
                    FristNode = fastnode;
                    LastNode.Next = FristNode;
                    isDeleteFlag = true;

                    if(FristNode != LastNode) lownode.Index--;
                }

                fastnode = fastnode.Next;
            }

            //找到指针
            if (fastnode.Index == number && isDeleteFlag == false)
            {
                deleteNode = fastnode;
                lownode.Next = fastnode.Next;
                fastnode = lownode.Next;
                isDeleteFlag = true;

                //删除的节点为最后一个时
                if (fastnode == FristNode) 
                {
                    LastNode = lownode;
                    break;
                } 
            }

            //删除元素后，后续元素下标减1
            if (isDeleteFlag) 
            {
                fastnode.Index--;
            }

            //指针指向下一位
            lownode = lownode.Next;
            fastnode = fastnode.Next;

        } while (fastnode != FristNode);

        if (!isDeleteFlag) 
        {
            throw new IndexOutOfRangeException("not found node.");
        }

        return deleteNode;
    }

    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="number">下标</param>
    /// <param name="data">数据</param>
    /// <returns></returns>
    /// <exception cref="NullReferenceException">linkedlist is null.</exception>
    /// <exception cref="IndexOutOfRangeException">not found node.</exception>
    public RingSingleLinkedList<T> Update(int number,T data) 
    {
        var isUpdateFlag = false;
        if (FristNode == null || LastNode == null)
        {
            throw new NullReferenceException("linkedlist is null.");
        }
        LinkedNode<T> node = FristNode;

        do
        {
            if (node.Index == number) 
            {
                node.Data = data;
                isUpdateFlag = true;
                break;
            }
            node = node.Next;
        } while (node != FristNode);

        if (!isUpdateFlag)
        {
            throw new IndexOutOfRangeException("not found node.");
        }

        return this;
    }

    /// <summary>
    /// 空判
    /// </summary>
    /// <returns>true:为空，false:非空</returns>
    public bool IsNull() 
    {
        return (FristNode == null || LastNode == null);
    }


    /// <summary>
    /// 字符串化
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        string info = "";
        if (FristNode == null || LastNode == null) 
        {
            return "null.";
        }
        LinkedNode<T> node = FristNode;
        do
        {
            info += node.ToString() + "\n";
            node = node.Next;
        } while (node != FristNode);

        return info;
    }
}
